<template>
  <div class="wrapper">
    <div class="titleStyle">
      <span>
        基本设置
      </span>
    </div>
    <div class="contentStyle">
      <el-form ref="form" :model="baseData" :rules="submitRules" label-width="80px" size="mini">
        <el-form-item label="接口名称" prop="apiName">
          <el-input v-model="baseData.apiName"></el-input>
        </el-form-item>
        <el-form-item label="接口分类" prop="apiClassify">
          <el-input v-model="baseData.apiClassify"></el-input>
        </el-form-item>
        <el-form-item label="接口路径">
          <el-row>
            <el-col :span="4">
              <el-select @change="changeApiType" style="width: 100px" size="mini" v-model="baseData.apiType" placeholder="请选择">
                <el-option
                    v-for="item in apiTypes"
                    :key="item.value"
                    :label="item.label"
                    :value="item.value">
                </el-option>
              </el-select>
            </el-col>
            <el-col :span="20">
              <el-form-item prop="apiUrl">
                <el-input v-model="baseData.apiUrl"></el-input>
              </el-form-item>
            </el-col>
          </el-row>
        </el-form-item>
      </el-form>
    </div>
    <div class="titleStyle">
      <span>
        请求参数设置
      </span>
    </div>
    <div class="requestTypeRadioStyle">
      <el-radio-group v-model="requestTypeRadio">
        <el-radio-button v-if="baseData.apiType==1 || baseData.apiType==2 || baseData.apiType==3 || baseData.apiType==6" label="Body"></el-radio-button>
        <el-radio-button label="Query"></el-radio-button>
        <el-radio-button label="Headers"></el-radio-button>
      </el-radio-group>
    </div>
    <div v-if="requestTypeRadio=='Body'" class="contentRequestStyle">
      <div class="selectRequestTypeStyle">
        <el-radio v-model="selectRequestType" :label="0">form</el-radio>
        <el-radio v-model="selectRequestType" :label="1">json</el-radio>
      </div>
      <div v-if="selectRequestType == 1" class="jsonRequestStyle">
        <el-button @click="importRequestJson()" class="parseJson" size="mini" type="primary" plain>导入json</el-button>
        <el-tree style="margin-bottom: 20px"
                 :data="requestJsonData"
                 node-key="id"
                 default-expand-all
                 :expand-on-click-node="false">
          <span class="custom-tree-node" slot-scope="{ node, data }">
            <el-input :disabled="data.disabled" :style="'width: ' + (280 - (node.level-1)*18) + 'px'" size="mini" v-model="data.field" placeholder="字段名称"></el-input>
            <el-switch
                v-model="data.required">
            </el-switch>
            <el-select @change="(selectValue) => changeSelectFieldType(selectValue, node, data)" style="width: 100px" size="mini" v-model="data.fieldType" placeholder="请选择">
              <el-option
                  v-for="item in fileTypes"
                  :key="item.value"
                  :label="item.label"
                  :value="item.value">
              </el-option>
            </el-select>
            <el-input style="width: 410px" size="mini" v-model="data.remarks" placeholder="备注"/>
            <span>
              <i class="el-icon-circle-plus" v-if="(data.fieldType == 2 || data.fieldType == 3) && !data.append" @click="() => append(data)"/>
              <i class="el-icon-remove" @click="() => remove(node, data)" v-if="!data.disabled"/>
            </span>
          </span>
        </el-tree>
        <el-dialog
            title="导入JSON"
            :visible.sync="parseJsonDialog"
            width="60%">
          <el-input
            type="textarea"
            :rows="16"
            placeholder="请输入内容"
            v-model="parseJsonStr">
          </el-input>
          <span slot="footer" class="dialog-footer">
            <el-button @click="parseJsonDialog = false">取 消</el-button>
            <el-button type="primary" @click="parseRequestJson()">确 定</el-button>
          </span>
        </el-dialog>
      </div>
      <div v-if="selectRequestType == 0" class="formRequestStyle">
        <el-button @click="formAdd()" class="queryAdd" size="mini" type="primary" plain>添加form参数</el-button>
        <div class="queryItem" v-for="item in formData">
          <el-row :gutter="3">
            <el-col :span="4">
              <el-input v-model="item.field" placeholder="字段名称" size="mini"/>
            </el-col>
            <el-col :span="3">
              <el-select style="width: 100%" size="mini" v-model="item.fieldType" placeholder="类型">
                <el-option
                    v-for="item in formFieldTypes"
                    :key="item.value"
                    :label="item.label"
                    :value="item.value">
                </el-option>
              </el-select>
            </el-col>
            <el-col :span="3">
              <el-select style="width: 100%" size="mini" v-model="item.required" placeholder="必填">
                <el-option
                    v-for="item in queryFileTypes"
                    :key="item.value"
                    :label="item.label"
                    :value="item.value">
                </el-option>
              </el-select>
            </el-col>
            <el-col :span="6">
              <el-input placeholder="参数示例" v-model="item.example" size="mini"/>
            </el-col>
            <el-col :span="7">
              <el-input placeholder="备注" v-model="item.remarks" size="mini"/>
            </el-col>
            <el-col :span="1" class="queryItemDelete">
              <i v-if="formData.length > 1" @click="formDelete(item)" class="el-icon-delete"/>
            </el-col>
          </el-row>
        </div>
      </div>
    </div>
    <div v-if="requestTypeRadio=='Query'" class="contentRequestQueryStyle">
      <el-button @click="queryAdd()" class="queryAdd" size="mini" type="primary" plain>添加Query参数</el-button>
      <div class="queryItem" v-for="item in queryData">
        <el-row :gutter="3">
          <el-col :span="4">
            <el-input v-model="item.field" placeholder="字段名称" size="mini"/>
          </el-col>
          <el-col :span="3">
            <el-select style="width: 100%" size="mini" v-model="item.required" placeholder="必填">
              <el-option
                  v-for="item in queryFileTypes"
                  :key="item.value"
                  :label="item.label"
                  :value="item.value">
              </el-option>
            </el-select>
          </el-col>
          <el-col :span="6">
            <el-input placeholder="参数示例" v-model="item.example" size="mini"/>
          </el-col>
          <el-col :span="10">
            <el-input placeholder="备注" v-model="item.remarks" size="mini"/>
          </el-col>
          <el-col :span="1" class="queryItemDelete">
            <i @click="queryDelete(item)" class="el-icon-delete"/>
          </el-col>
        </el-row>
      </div>
    </div>
    <div v-if="requestTypeRadio=='Headers'" class="contentRequestHeadersStyle">
      <el-button @click="headersAdd()" class="queryAdd" size="mini" type="primary" plain>添加Header</el-button>
      <div class="queryItem" v-for="item in headersData">
        <el-row :gutter="3">
          <el-col :span="4">
            <el-input v-model="item.key" placeholder="key" size="mini"/>
          </el-col>
          <el-col :span="3">
            <el-input v-model="item.value" placeholder="value" size="mini"/>
          </el-col>
          <el-col :span="6">
            <el-input v-model="item.example" placeholder="参数示例" size="mini"/>
          </el-col>
          <el-col :span="10">
            <el-input v-model="item.remarks" placeholder="备注" size="mini"/>
          </el-col>
          <el-col :span="1" class="queryItemDelete">
            <i @click="headersDelete(item)" class="el-icon-delete"/>
          </el-col>
        </el-row>
      </div>
    </div>
    <div class="titleStyle">
      <span>
        返回参数设置
      </span>
    </div>
    <div class="contentRequestStyle">
      <el-button @click="importResponseJson()" style="margin-top: 10px" class="parseJson" size="mini" type="primary" plain>导入json</el-button>
      <el-tree style="margin-bottom: 20px"
               :data="responseJsonData"
               node-key="id"
               default-expand-all
               :expand-on-click-node="false">
      <span class="custom-tree-node" slot-scope="{ node, data }">
        <el-input :disabled="data.disabled" :style="'width: ' + (280 - (node.level-1)*18) + 'px'" size="mini" v-model="data.field" placeholder="字段名称"></el-input>
        <el-switch
            v-model="data.required">
        </el-switch>
        <el-select @change="(selectValue) => changeSelectFieldType(selectValue, node, data)" style="width: 100px" size="mini" v-model="data.fieldType" placeholder="请选择">
          <el-option
              v-for="item in fileTypes"
              :key="item.value"
              :label="item.label"
              :value="item.value">
          </el-option>
        </el-select>
        <el-input style="width: 410px" size="mini" v-model="data.remarks" placeholder="备注"/>
        <span>
          <i class="el-icon-circle-plus" v-if="(data.fieldType == 2 || data.fieldType == 3) && !data.append" @click="() => append(data)"/>
          <i class="el-icon-remove" @click="() => remove(node, data)" v-if="!data.disabled"/>
        </span>
      </span>
      </el-tree>
      <el-dialog
          title="导入JSON"
          :visible.sync="parseResponseDialog"
          width="60%">
        <el-input
            type="textarea"
            :rows="16"
            placeholder="请输入内容"
            v-model="parseResponseJsonStr">
        </el-input>
        <span slot="footer" class="dialog-footer">
            <el-button @click="parseResponseDialog = false">取 消</el-button>
            <el-button type="primary" @click="parseResponseJson()">确 定</el-button>
          </span>
      </el-dialog>
    </div>
    <div class="titleStyle">
      <span>
        备注
      </span>
    </div>
    <div class="remarksStyle">
      <el-input
          type="textarea"
          :rows="20"
          placeholder="备注"
          v-model="remarks">
      </el-input>
    </div>
    <div class="saveButtonStyle">
      <el-button @click="saveAll()" size="medium" type="info">保存</el-button>
    </div>
  </div>
</template>

<script>
export default {
  name: "OpenApiManage",
  data: function() {
    return {
      // 请求的json参数
      requestJsonData: [{
        id: 1,
        field: 'root',
        required: true,
        fieldType: 3,
        remarks: null,
        disabled: true,
        append: false,
        children: []
      }],
      // 响应的json参数
      responseJsonData: [{
        id: 1,
        field: 'root',
        required: true,
        fieldType: 3,
        remarks: null,
        disabled: true,
        append: false,
        children: []
      }],
      // json参数类型
      fileTypes: [
      {
        value: 0,
        label: 'string'
      },{
        value: 1,
        label: 'number'
      },{
        value: 2,
        label: 'array'
      },{
        value: 3,
        label: 'object'
      },{
        value: 4,
        label: 'boolean'
      },{
        value: 5,
        label: 'integer'
      }
      ],
      // Query参数类型 0非必须 1必须
      queryFileTypes: [
        {
          value: 0,
          label: "非必须"
        },
        {
          value: 1,
          label: "必须"
        }
      ],
      id: 0,
      // 接口基础参数
      baseData: {
        apiName: '',
        apiClassify: '',
        apiType: 1,
        apiUrl: ''
      },
      // 请求类型选择
      requestTypeRadio: 'Body',
      // 备注
      remarks: '',
      // Query参数parameter
      queryData: [
        // {
        //   id: 0,
        //   field: '',
        //   required: 0,
        //   example: '',
        //   remarks: ''
        // }
      ],
      // 请求头数据
      headersData: [
        // {
        //   id: 0,
        //   key: '',
        //   value: '',
        //   example: '',
        //   remarks: ''
        // }
      ],
      // 接口类型
      apiTypes: [
        {
          value: 0,
          label: 'GET'
        },
        {
          value: 1,
          label: 'POST'
        },
        {
          value: 2,
          label: 'PUT'
        },
        {
          value: 3,
          label: 'DELETE'
        },
        {
          value: 4,
          label: 'HEAD'
        },
        {
          value: 5,
          label: 'OPTIONS'
        },
        {
          value: 6,
          label: 'PATCH'
        }
      ],
      // 选择请求的类型,1json 0form
      selectRequestType: 1,
      // form表单的数据格式
      formData: [
        {
          id: 0,
          field: '',
          fieldType: 0,
          required: 0,
          example: '',
          remarks: ''
        }
      ],
      // form表单的类型
      formFieldTypes: [
        {
          value: 0,
          label: 'text'
        },
        {
          value: 1,
          label: 'file'
        }
      ],
      // 请求json的弹框
      parseJsonDialog: false,
      // 请求的json字符串
      parseJsonStr: '',
      // 输入响应json的弹框
      parseResponseDialog: false,
      // 解析响应json的字符串
      parseResponseJsonStr: '',
      // 保存前参数校验
      submitRules: {
        apiName: [
          { required: true, message: '接口名称不能为空', trigger: 'change' }
        ],
        apiClassify: [
          { required: true, message: '接口分类不能为空', trigger: 'change' }
        ],
        apiUrl: [
          { required: true, message: '接口路径不能为空', trigger: 'change' }
        ],
      },
      // 整体保存
      submitData: {
        // 数据类型, 0-openapi
        type: 0,
        // 接口名称
        apiName: '',
        // 接口分类
        apiClassify: '',
        // 接口类型
        apiType: null,
        // 接口地址
        apiUrl: null,
        // 备注
        remarks: null,
        // query参数
        queryParameter: null,
        // headers请求头
        headers: null,
        // 请求体
        requestBody: {
          requestBodyType: null,
          form: null,
          json: null
        },
        // json类型响应参数
        response: null
      }
    }
  },
  methods: {
    /**
     * Json参数树添加节点
     */
    append(data, disabled, field) {
      if (!disabled) {
        disabled = false
      }
      this.id++
      const newChild = { id: this.id, children: [], disabled: disabled, field: field, fieldType: 0 };
      if (!data.children) {
        this.$set(data, 'children', []);
      }
      data.children.push(newChild);
    },
    /**
     * Json参数树移除节点
     */
    remove(node, data) {
      const parent = node.parent
      const children = parent.data.children || parent.data
      const index = children.findIndex(d => d.id === data.id)
      children.splice(index, 1)
    },
    /**
     * Json参数树变化字段类型触发函数
     */
    changeSelectFieldType(selectValue, node, data) {
      data.children = []
      if (selectValue == 2) {
        data.append = true
        this.append(data, true, "item")
      } else {
        data.append = false
      }
    },
    /**
     * Query参数添加
     */
    queryAdd() {
      this.id++
      const newRow = {id: this.id, filed: '', required: 0, example: '', remarks: ''}
      this.queryData.push(newRow)
    },
    /**
     * Query参数删除
     */
    queryDelete(item) {
      const index = this.queryData.findIndex(d => d.id === item.id)
      this.queryData.splice(index, 1)
    },
    /**
     * 请求头添加
     */
    headersAdd() {
      this.id++
      const newRow = {id: this.id, key: '', value: '', example: '', remarks: ''}
      if (this.headersData == undefined) {
        this.headersData = []
      }
      this.headersData.push(newRow)
    },
    /**
     * 请求头删除
     */
    headersDelete(item) {
      const index = this.headersData.findIndex(d => d.id === item.id)
      this.headersData.splice(index, 1)
    },
    /**
     * form请求参数添加
     */
    formAdd() {
      this.id++
      const newRow = {id: this.id, filed: '',fieldType: 0, required: 0, example: '', remarks: ''}
      this.formData.push(newRow)
    },
    /**
     * form请求参数删除
     */
    formDelete(item) {
      const index = this.formData.findIndex(d => d.id === item.id)
      this.formData.splice(index, 1)
    },
    /**
     * 接口类型变化触发函数
     */
    changeApiType(type) {
      if (type == 1 || type == 3 || type == 2 || type == 6) {
        this.requestTypeRadio = 'Body'
      } else {
        this.requestTypeRadio = 'Query'
      }
    },
    /**
     * 全局保存按钮
     */
    saveAll() {
      this.$refs['form'].validate((valid) => {
        if (valid) {
          this.submitData.apiName = this.baseData.apiName
          this.submitData.apiClassify = this.baseData.apiClassify
          this.submitData.apiType = this.baseData.apiType
          this.submitData.apiUrl = this.baseData.apiUrl
          this.submitData.remarks = this.remarks
          this.submitData.queryParameter = this.queryData
          this.submitData.headers = this.headersData
          this.submitData.requestBody.requestBodyType = this.selectRequestType
          this.submitData.requestBody.form = this.formData
          this.submitData.requestBody.json = this.requestJsonData
          this.submitData.response = this.responseJsonData
          console.log(this.submitData)
          this.$confirm('确定保存?', '提示', {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: 'warning'
          }).then(() => {
            this.sendRequest()
          }).catch(() => {
            this.$message({
              type: 'info',
              message: '取消保存'
            });
          });
        } else {
          this.$message({
            type: 'error',
            message: '请正确填写接口参数'
          });
          return false;
        }
      });
    },
    /**
     * 发送请求
     */
    async sendRequest() {
      let res = await this.$http.post('/api/apiManage/add', this.submitData)
      if(res.code == 0){
        this.$message({
          message: res.message,
          type: 'success'
        })
        this.goBack()
      }
    },
    /**
     * 导入请求json按钮
     */
    importRequestJson() {
      this.parseJsonDialog = true
    },
    /**
     * 解析请求json
     */
    parseRequestJson() {
      this.parseJsonDialog = false
      const result = this.parseJsonToTree(JSON.parse(this.parseJsonStr))
      result[0].field = 'root'
      this.requestJsonData = result
    },
    /**
     * 导入响应json按钮
     */
    importResponseJson() {
      this.parseResponseDialog = true
    },
    /**
     * 解析响应的json
     */
    parseResponseJson() {
      this.parseResponseDialog = false
      const result = this.parseJsonToTree(JSON.parse(this.parseResponseJsonStr))
      result[0].field = 'root'
      this.responseJsonData = result
    },
    /**
     * 解析对象
     * @param jsonObj json对象
     * @return 解析结果Tree
     */
    parseJsonToTree(jsonObj) {
      let result = []
      if (typeof jsonObj == 'object') {
        let row = this.parseObjectToTreeRow('item', jsonObj, true)
        if (!row.children) {
          this.$set(row, 'children', []);
        }
        for (let key in jsonObj) {
          const value = jsonObj[key]
          if (typeof value == 'object' && !(value instanceof Array) && value != null) {
            row.children.push(this.parseJsonToTree(value))
          } else if(value instanceof Array) {
            let arrayRowAppend = false
            if (typeof value[0] != 'object') {
              arrayRowAppend = true
            }
            let arrayRow = this.parseObjectToTreeRow(key, value, false, arrayRowAppend)
            if (!arrayRow.children) {
              this.$set(arrayRow, 'children', []);
            }
            arrayRow.children.push(this.parseJsonToTree(value[0])[0])
            row.children.push(arrayRow)
          } else {
            row.children.push(this.parseObjectToTreeRow(key, value, false))
          }
        }
        result.push(row)
      } else if (jsonObj instanceof Array) {
        let row = this.parseObjectToTreeRow('item', jsonObj, true)
        row.children.push(this.parseJsonToTree(jsonObj[0]))
        result.push(row)
      } else {
        result.push(this.parseObjectToTreeRow('item', jsonObj, true))
      }
      return result
    },
    /**
     * 解析一个字段
     * @param key
     * @param obj
     * @param disabled 是否能编辑字段名称
     * @param append 是否能添加
     * @returns {{field, disabled: boolean, id: number, fieldType: number, required: number, remarks: null, append: boolean}}
     */
    parseObjectToTreeRow(key, obj, disabled, append) {
      this.id++
      let newRow = null
      let fieldType = 0
      if (typeof obj == 'string' || obj == null) {
        fieldType = 0
      } else if (typeof obj == 'number') {
        fieldType = 1
      } else if (obj instanceof Array) {
        fieldType = 2
      } else if (typeof obj == 'object') {
        fieldType = 3
      } else if (typeof obj == 'boolean') {
        fieldType = 4
      } else if (typeof obj == 'integer') {
        fieldType = 5
      }
      newRow = {id: this.id, field: key, required: false, fieldType: fieldType, remarks: null, disabled: disabled, append: append, children: []}
      return newRow
    },
    /**
     * 返回列表页
     */
    goBack() {
      this.$router.push('/openApi/manage')
    },
  }
}
</script>

<style lang="scss" scoped>
.wrapper{
  //position: relative;
}
.titleStyle{
  border-left: 3px solid #409EFF;
  padding: 5px;
  margin-top: 8px;
  margin-bottom: 8px;
  span{
    font-size: 16px;
    color: #303133;
  }
}
.contentStyle{
  background-color: #F2F6FC;
  padding: 10px 120px;
  color: #606266;
}
.contentRequestStyle{
  background-color: #F2F6FC;
  padding:0px;
}
.parseJson{
  margin-left: 10px;
}
.selectRequestTypeStyle{
  padding: 10px;
}
.formRequestStyle{
  padding-left: 10px;
  padding-bottom: 10px;
}
.queryAdd{
  margin-bottom: 10px;
}
.contentRequestQueryStyle{
  background-color: #F2F6FC;
  padding: 10px;
}
.queryItem{
  margin-bottom: 5px;
}
.queryItem:last-child{
  margin-bottom: 0px;
}
.queryItemDelete{
  padding-top: 5px;
}
.contentRequestHeadersStyle{
  background-color: #F2F6FC;
  padding: 10px;
}
.el-tree{
  padding: 10px 0px;
  background-color: #F2F6FC;
  color: #606266;
  margin-bottom: 0px !important;
}
.el-form-item--mini.el-form-item{
  margin-bottom: 12px;
}
.el-form-item--mini:last-child{
  margin-bottom: 0px;
}
.requestTypeRadioStyle{
  text-align: center;
  width: 100%;
  padding-bottom: 10px;
}
.remarksStyle{
  background-color: #F2F6FC;
  color: #606266;
  padding: 10px 10px;
  margin-bottom: 40px;
}
.saveButtonStyle{
  margin-bottom: 10px;
  margin-top: 10px;
  padding: 10px;
  text-align: center;
  background-color: #F2F6FC;
  position: fixed;
  width: 895px;
  top: 735px;
  //top: 10px;
}
</style>
<style scoped>
/deep/ .el-tree-node__content {
  height: 32px;
}
</style>
